﻿using System;
using System.Collections.Generic;
using FinPlusCommon;
using FinPlusComponents;
using QLNet;
using u = FinPlusUtility.Utility;

namespace FinPlusAnalytics 
{
    public class Market : FinPlusComponent
    {
        public string Name { get; private set; }
        public DateTime TodaysDate { get; private set; }
        public double Tolerance { get; private set; }
        public bool IsObservable { get; private set; }

        private Dictionary<string, IPricingEngine> _engines;
        private Dictionary<string, YieldTermStructure> _curves;
        private Dictionary<string, RateHelper> _rateHelpers;
        private Dictionary<string, IborIndex> _indexs; 

        private Dictionary<string, RelinkableHandle<YieldTermStructure>> _linkedCurves;
        private Dictionary<string, RelinkableHandle<Instrument>> _bonds;
        private Dictionary<string, RelinkableHandle<Quote>> _quotes;
    

        //construct
        public Market(string name, DateTime todaysDate, double tolerance = 1.0e-15, bool isObservable = false)
        {
            Name = name;
            TodaysDate = todaysDate;
            Tolerance = tolerance;
            IsObservable = isObservable;

            _engines = new Dictionary<string, IPricingEngine>();
            _curves = new Dictionary<string, YieldTermStructure>();
            _rateHelpers = new Dictionary<string, RateHelper>();
            _indexs = new Dictionary<string, IborIndex>();

            _linkedCurves = new Dictionary<string, RelinkableHandle<YieldTermStructure>>();
            _bonds = new Dictionary<string, RelinkableHandle<Instrument>>();
            _quotes = new Dictionary<string, RelinkableHandle<Quote>>();
            Settings.setEvaluationDate(todaysDate);
        }

        //public
        public IPricingEngine GetEngine(string name)
        {
            if (_engines.ContainsKey(name))
                return _engines[name];

            throw new AnalyticsException(string.Format("engine {0} missing", name));
        }

        public void SetEngine(string name, IPricingEngine engine)
        {
            _engines[name] = engine;
        }

        public RelinkableHandle<YieldTermStructure> GetLinkedCurve(string name)
        {
            RelinkableHandle<YieldTermStructure> linkedCurve;
            if (!_linkedCurves.ContainsKey(name))
                _linkedCurves[name] = linkedCurve = new RelinkableHandle<YieldTermStructure>(new YieldTermStructure(), IsObservable);
            else
                linkedCurve = _linkedCurves[name];
            return linkedCurve;
        }

        public YieldTermStructure GetCurve(string name)
        {
            if (_curves.ContainsKey(name))
                return _curves[name];

            return null;
        }

        public void SetCurve(string name, YieldTermStructure yieldTermStructure)
        {
            _curves[name] = yieldTermStructure;
        }
        
        public RateHelper GetRateHelper(string name)
        {
            if (_rateHelpers.ContainsKey(name))
                return _rateHelpers[name];

            return null;
        }

        public void SetRateHelper(string name, RateHelper rateHelper)
        {
            _rateHelpers[name] = rateHelper;
        }

        public RelinkableHandle<Instrument> GetBond(string name)
        {
            RelinkableHandle<Instrument> bond;
            if (!_bonds.ContainsKey(name))
                _bonds[name] = bond = new RelinkableHandle<Instrument>(new Instrument(), IsObservable);
            else
                bond = _bonds[name];
            return bond;
        }

        public IborIndex GetIndex(string name)
        {
            if (_indexs.ContainsKey(name))
                return _indexs[name];

            return null;
        }

        public void SetIndex(string name, IborIndex index)
        {
            _indexs[name] = index;
        }

        public RelinkableHandle<Quote> GetQuote(string name)
        {
            RelinkableHandle<Quote> quote;
            if (!_quotes.ContainsKey(name))
                _quotes[name] = quote = new RelinkableHandle<Quote>(new Quote(), IsObservable);
            else
                quote = _quotes[name];
            return quote;
        }

        public object[] MarketValueTrade(Cache cache, string tradeId, string[] controls)
        {
            var trade = cache.Get(tradeId);
            var engineName = cache.EngineMap(tradeId);
            var engine  = GetEngine(engineName);
            trade.SetPricingEngine(engine);
            var res = trade.Value(controls);

            return res;
        }
    }
}
